package login

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"log"
	"muziai-server/global"
	"muziai-server/models"
	"muziai-server/models/ctype"
	"muziai-server/service/common"
	"muziai-server/service/redis"
	"muziai-server/service/user_service"
	"muziai-server/service/wx/auth"
	"muziai-server/service/wx/handle"
	"muziai-server/utils/random"
	"muziai-server/utils/req"
	"muziai-server/utils/res"
	"time"
)

type WxLoginService struct {
	WxHandleService handle.WxHandleService
	WxRedisService  redis.RedisService
	userservice     user_service.UserService
}

var conunt int = 1
var ctx = context.Background()

// WXTextMsg 微信文本消息结构体
type WXQrEventMsg struct {
	ToUserName   string
	FromUserName string
	CreateTime   int64
	MsgType      string
	Event        string
	EventKey     string
	Ticket       string
}

// 定义结构体来匹配 JSON 数据
type QrCodeRequest struct {
	ExpireSeconds int          `json:"expire_seconds"`
	ActionName    string       `json:"action_name"`
	ActionInfo    QrCodeAction `json:"action_info"`
}
type QrCodeResponse struct {
	Ticket        string `json:"ticket"`
	ExpireSeconds int    `json:"expire_seconds"`
	URL           string `json:"url"`
}

type QrCodeAction struct {
	Scene QrCodeScene `json:"scene"`
}
type QrCodeScene struct {
	SceneID int `json:"scene_id"`
}

func (w WxLoginService) GetQrCodeUri(c *gin.Context) {
	conunt++ //确保sceneId不重复
	token := auth.Access_Token
	// 构建请求 URL
	getickeurl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s", token)

	// 构建请求体
	qrCodeRequestBody := QrCodeRequest{
		ExpireSeconds: 60,
		ActionName:    "QR_SCENE",
		ActionInfo: QrCodeAction{
			Scene: QrCodeScene{
				SceneID: conunt,
			},
		},
	}
	headers := map[string]string{}
	body, err := req.HttpPost(getickeurl, headers, qrCodeRequestBody)
	if err != nil {
		res.FailWithError(c, err)
		return
	}
	// 解析 JSON 响应
	var qrCodeResponse QrCodeResponse

	err = json.Unmarshal(body, &qrCodeResponse)
	if err != nil {
		res.FailWithError(c, err)
		return
	}

	getqrurl := fmt.Sprintf("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s", qrCodeResponse.Ticket)
	var qrinfo = map[string]any{
		"qruri":  getqrurl,
		"ticket": qrCodeResponse.Ticket,
	}
	//获取二维码,二维码ticket存入redis,默认表示未完成扫码,false
	err = global.Redis.HMSet(ctx, qrCodeResponse.Ticket, map[string]interface{}{
		"scanned": false,
		"openid":  "",
		"token":   "", // 初始状态为 false，表示尚未扫码
	}).Err()
	if err != nil {
		return
	}
	// 设置该 ticket 的过期时间为 60 秒
	global.Redis.Expire(context.Background(), qrCodeResponse.Ticket, time.Second*60)

	res.Ok(c, qrinfo, "成功返回")

}

// WXMsgReceive 微信消息接收
func (w WxLoginService) WXMQrEventReceive(c *gin.Context) {
	var qreventmsg WXQrEventMsg
	err := c.ShouldBindXML(&qreventmsg)
	if err != nil {
		log.Printf("[消息接收] - XML数据包解析失败: %v\n", err)
		return
	}
	//log.Printf("[消息接收] - 收到消息, 消息类型为: %s, 消息内容为: %s\n", textMsg.MsgType, textMsg.Content)
	var fromUserName = qreventmsg.FromUserName
	var toUserName = qreventmsg.ToUserName
	var ticket = qreventmsg.Ticket
	fmt.Println(qreventmsg)

	//检查是否被扫描
	iscanned, err := w.WxRedisService.IsTicketScanned(ticket)
	//如果是扫码并且redis没有该二维码的ticket
	if qreventmsg.Ticket != "" && iscanned == false {
		// 更新扫码状态
		w.WxRedisService.UpdateFieldValue(ticket, "scanned", true)
		w.WxRedisService.UpdateFieldValue(ticket, "openid", fromUserName)
		switch qreventmsg.Event {
		case "subscribe":
			//这是关注的用户
			err = w.loginWxUser(c, fromUserName, ticket)
			if err != nil {
				w.WxHandleService.SimpleReply(c, toUserName, fromUserName, "服务错误，请联系管理员") // 关注后的默认回复
				return
			}
			w.WxHandleService.SimpleReply(c, toUserName, fromUserName, "感谢你的关注,登录成功了哦!!!") // 关注后的默认回复

		case "SCAN":
			//这是新用户
			err = w.loginWxUser(c, fromUserName, ticket)
			if err != nil {
				w.WxHandleService.SimpleReply(c, toUserName, fromUserName, "服务错误，请联系管理员")
				return
			}
			w.WxHandleService.SimpleReply(c, toUserName, fromUserName, "友友登录成功了哦!!!")
		} // 调用gpt回复
	} else {
		w.WxHandleService.SimpleReply(c, toUserName, fromUserName, "欢迎来到木子AI公众号,请正确扫码登录") // 未定义类型的回复
	}

}

func (w WxLoginService) findUser(openId string) (bool, models.UserModel) {
	var user models.UserModel
	err := global.DB.Take(&user, "open_id=?", openId).Error

	if errors.Is(err, gorm.ErrRecordNotFound) {
		return false, user // 没有找到用户，返回 false
	}

	if err != nil {
		panic(err.Error()) // 发生错误，抛出 panic
	}

	return true, user // 找到用户，返回 true
}

func (w WxLoginService) createWxUser(openId string) (error, models.UserModel) {
	var user = models.UserModel{
		Nickname:       fmt.Sprintf("木子AI用户_%s", random.RandString(4)),
		Username:       fmt.Sprintf("木子AI_%s", random.RandString(10)),
		OpenID:         openId,
		RegisterSource: ctype.WxRegister,
		Role:           ctype.AuthRole,
	}

	err := global.DB.Create(&user).Error
	return err, user
}

func (w WxLoginService) loginWxUser(c *gin.Context, openId string, ticket string) error {
	log := common.GetLog(c)
	log.ShowResponse()

	log.SetTitle("用户公众号登录")
	//查询此用户
	isfinde, user := w.findUser(openId)
	if isfinde {

		token, err := w.userservice.UserLogin(c, user)
		//找到了直接走登录逻辑
		if err != nil {
			logrus.Fatal("生成token失败")
			return err
		}
		//设置token和完成扫码
		w.WxRedisService.UpdateFieldValue(ticket, "token", token)
		logrus.Infof("用户已存在:jwttoken:%s", token)

	} else {
		//注册逻辑
		err, user := w.createWxUser(openId)
		if err != nil {
			logrus.Fatal("用户创建失败")
			return err
		}
		//注册成功后
		token, err := w.userservice.UserLogin(c, user)

		if err != nil {
			logrus.Fatal("生成token失败")
			return err
		}
		//设置token和完成扫码
		w.WxRedisService.UpdateFieldValue(ticket, "token", token)
		//给注册成功的用户送积分
		w.userservice.UserScope(global.DB, user.ID, global.Config.AI.RegisterUserScope)
		logrus.Infof("用户注册成功:jwttoken:%s", token)

	}

	return nil
}

func (w WxLoginService) WXQrGetToken(c *gin.Context) {

	// 从 URL 查询参数中获取 ticket
	ticket, _ := c.GetQuery("ticket")
	exists, err := global.Redis.Exists(ctx, ticket).Result()
	if err != nil {
		res.FailWithMsg(c, err.Error())
		return
	}

	if exists == 1 {
		token, err := global.Redis.HGet(context.Background(), ticket, "token").Result()
		if err != nil {
			// 处理其他 Redis 错误
			res.FailWithMsg(c, err.Error())
			return
		}

		if token == "" {
			res.FailWithMsg(c, "token不存在")
			return
		}
		// 返回 token 成功结果
		res.OkWithData(c, token)
	} else {
		res.FailWithMsg(c, "ticket失效或不存在")
		return
	}

}
